﻿using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using Microsoft.SPOT;
using Microsoft.SPOT.Hardware;
using SecretLabs.NETMF.Hardware;
using SecretLabs.NETMF.Hardware.NetduinoPlus;

public class HelloPachubeSockets
{
    public static void Main()
    {
        const string apiKey = "<insert your API key here>";
        const string feedId = "<insert your feed ID here>";
        const int samplingPeriod = 10000;   // 10 seconds

        const double maxVoltage = 3.3;
        const int maxAdcValue = 1023;

        var voltagePort = new AnalogInput(Pins.GPIO_PIN_A2);
        var lowPort = new OutputPort(Pins.GPIO_PIN_A0, false);
        var highPort = new OutputPort(Pins.GPIO_PIN_A4, true);

        Socket connection = null;

        while (true)   // main loop
        {
            WaitUntilNextPeriod(samplingPeriod);

            Debug.Print("time: " + DateTime.Now);
            Debug.Print("memory available: " + Debug.GC(true));

            if (connection == null)   // create connection
            {
                try
                {
                    connection = Connect("api.pachube.com",
                        samplingPeriod / 2);
                }
                catch
                {
                    Debug.Print("connection error");
                }
            }

            if (connection != null)
            {
                try
                {
                    int rawValue = voltagePort.Read();
                    double value = (rawValue * maxVoltage) / maxAdcValue;
                    string sample = "voltage," + value.ToString("f");
                    Debug.Print("new sample: " + sample);
                    SendRequest(connection, apiKey, feedId, sample);
                }
                catch (SocketException)
                {
                    connection.Close();
                    connection = null;
                }
            }
        }
    }

    static Socket Connect(string host, int timeout)
    {
        // look up host's domain name, to find IP address(es)
        IPHostEntry hostEntry = Dns.GetHostEntry(host);
        // extract a returned address
        IPAddress hostAddress = hostEntry.AddressList[0];
        IPEndPoint remoteEndPoint = new IPEndPoint(hostAddress, 80);

        // connect!
        Debug.Print("connect...");
        var connection = new Socket(AddressFamily.InterNetwork,
            SocketType.Stream, ProtocolType.Tcp);
        connection.Connect(remoteEndPoint);
        connection.SetSocketOption(SocketOptionLevel.Tcp,
            SocketOptionName.NoDelay, true);
        connection.SendTimeout = timeout;
        return connection;
    }

    static void SendRequest(Socket s, string apiKey, string feedId,
        string content)
    {
        byte[] contentBuffer = Encoding.UTF8.GetBytes(content);
        const string CRLF = "\r\n";
        var requestLine =
            "PUT /v2/feeds/" + feedId + ".csv HTTP/1.1" + CRLF;
        byte[] requestLineBuffer = Encoding.UTF8.GetBytes(requestLine);
        var headers =
            "Host: api.pachube.com" + CRLF +
            "X-PachubeApiKey: " + apiKey + CRLF +
            "Content-Type: text/csv" + CRLF +
            "Content-Length: " + contentBuffer.Length + CRLF +
            CRLF;
        byte[] headersBuffer = Encoding.UTF8.GetBytes(headers);
        s.Send(requestLineBuffer);
        s.Send(headersBuffer);
        s.Send(contentBuffer);
    }

    static void WaitUntilNextPeriod(int period)
    {
        long now = DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond;
        var offset = (int)(now % period);
        int delay = period - offset;
        Debug.Print("sleep for " + delay + " ms\r\n");
        Thread.Sleep(delay);
    }
}
